


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dp1.titandevelop.titano.service;

import dp1.titandevelop.titano.bean.Estado;
import dp1.titandevelop.titano.persistent.Almacen;
import dp1.titandevelop.titano.persistent.AlmacenXProducto;
import dp1.titandevelop.titano.persistent.Producto;
import dp1.titandevelop.titano.persistent.Zona;
import dp1.titandevelop.titano.view.LoginT;
import java.util.ArrayList;
import java.util.List;
import org.apache.cayenne.DataObjectUtils;
import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.access.DataContext;
import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionFactory;
import org.apache.cayenne.query.SQLTemplate;
import org.apache.cayenne.query.SelectQuery;

/**
 *
 * @author Yulian
 */
public class AlmacenService {

    public List<AlmacenXProducto> obtenerTemporal(){
        ObjectContext c = DataContext.createDataContext();
        String cadena = "SELECT * FROM almacen_x_producto WHERE ESTADO > 0 and idalmacen in (select idalmacen from almacen where descripcion ilike '%Temporal%')";
        SQLTemplate query = new SQLTemplate(AlmacenXProducto.class,cadena);        
        List<AlmacenXProducto> almacenes = c.performQuery(query);       
        return almacenes;        
    }
    
    public AlmacenXProducto obtenerTemporalPorProd(int idprod){
        ObjectContext c = DataContext.createDataContext();
        String cadena = "SELECT * FROM almacen_x_producto WHERE ESTADO > 0 and  idproducto = "+idprod+" and idalmacen in (select idalmacen from almacen where descripcion ilike '%Temporal%')";
        SQLTemplate query = new SQLTemplate(AlmacenXProducto.class,cadena);        
        List<AlmacenXProducto> almacenes = c.performQuery(query); 
        if(!almacenes.isEmpty())
            return almacenes.get(0);
        else 
            return null;        
    }
    public Almacen obtenerTemporalPorProceso(String descrip){
        
        ObjectContext c = DataContext.createDataContext();
        String cadena = "select * from almacen where descripcion ilike '%Temporal%' and descripcion ilike '%"+descrip+"%'";
        SQLTemplate query = new SQLTemplate(Almacen.class,cadena);        
        List<Almacen> almacenes = c.performQuery(query);
        if (almacenes.isEmpty())
            return null;
        else
            return almacenes.get(0); 
    }
    public Almacen buscarPorId(ObjectContext c, int id) {
        
        Expression q1 = ExpressionFactory.matchExp(Almacen.IDALMACEN_PK_COLUMN, id);
        Expression q2= ExpressionFactory.greaterExp(Almacen.ESTADO_PROPERTY,0);
        Expression q0=q1.andExp(q2);
        SelectQuery s = new SelectQuery(Almacen.class, q0);
        return (Almacen) DataObjectUtils.objectForQuery(c, s);
    }
        
     public List<Almacen> buscarPorZona(ObjectContext c, int id) {
         
        String cadena = "SELECT * FROM ALMACEN WHERE ESTADO > 0 and idzona ="+id+"";
        SQLTemplate query = new SQLTemplate(Almacen.class,cadena);        
        List<Almacen> almacenes = c.performQuery(query);       
        return almacenes;
    }
     
    public void insertar(int idZona, String descripcion, String direccion, List<Integer> idproductos, List<Integer> capacidades) {
        
        ObjectContext context = DataContext.createDataContext();
        
        Expression qualifier = ExpressionFactory.matchExp(Zona.IDZONA_PROPERTY,String.valueOf(idZona));
        SelectQuery select = new SelectQuery(Zona.class, qualifier);
        Zona z = (Zona) DataObjectUtils.objectForQuery(context, select);
        
        Estado e = new Estado();
        Almacen a = context.newObject(Almacen.class);        
        a.setDescripcion(descripcion);
        a.setDireccion(direccion);
        a.setEstado(e.getSinUsar());
        a.setToZona(z);
        
        int cont=0;
        while (cont<capacidades.size())
        {   AlmacenXProducto p = context.newObject(AlmacenXProducto.class);
        
            Expression qualifiers = ExpressionFactory.matchExp(Producto.IDPRODUCTO_PROPERTY,String.valueOf(idproductos.get(cont)));
            SelectQuery selects = new SelectQuery(Producto.class, qualifiers);
            Producto prod = (Producto)DataObjectUtils.objectForQuery(context, selects);
            
            p.setToProducto(prod);
            p.setToAlmacen(a);
            p.setCapacidad(capacidades.get(cont));
            p.setEstado(e.getSinUsar());
            p.setStock(0);
            context.commitChanges(); 
            cont++;
        }       
        
         String usuario=LoginT.userLogin.getUsuario();
        String perfil=LoginT.perfilLogin.getDescripcion();
        AuditoriaService as = new AuditoriaService();
        as.auditoriaInsert(usuario, perfil, "Almacen");
    }
    
    public void insertar(int idZona, String descripcion, String direccion) {
        
        ObjectContext context = DataContext.createDataContext();
        
        Expression qualifier = ExpressionFactory.matchExp(Zona.IDZONA_PROPERTY,String.valueOf(idZona));
        SelectQuery select = new SelectQuery(Zona.class, qualifier);
        Zona z = (Zona) DataObjectUtils.objectForQuery(context, select);
        
        Estado e = new Estado();
        Almacen a = context.newObject(Almacen.class);        
        a.setDescripcion(descripcion);
        a.setDireccion(direccion);
        a.setEstado(e.getSinUsar());
        a.setToZona(z);
        
        context.commitChanges();
         String usuario=LoginT.userLogin.getUsuario();
        String perfil=LoginT.perfilLogin.getDescripcion();
        AuditoriaService as = new AuditoriaService();
        as.auditoriaInsert(usuario, perfil, "Almacen");
    }
     public void insertar_masivo(int idAlmacen, int idZona, String descripcion, String direccion) {
        
        ObjectContext context = DataContext.createDataContext();
        
        Expression qualifier = ExpressionFactory.matchExp(Zona.IDZONA_PROPERTY,String.valueOf(idZona));
        SelectQuery select = new SelectQuery(Zona.class, qualifier);
        Zona z = (Zona) DataObjectUtils.objectForQuery(context, select);
        
        Estado e = new Estado();
        Almacen a = context.newObject(Almacen.class);        
        a.setDescripcion(descripcion);
        a.setDireccion(direccion);
        a.setEstado(e.getSinUsar());
        a.setIdalmacen(idAlmacen);
        a.setToZona(z);
        
        context.commitChanges();
         String usuario=LoginT.userLogin.getUsuario();
        String perfil=LoginT.perfilLogin.getDescripcion();
        AuditoriaService as = new AuditoriaService();
        as.auditoriaInsert(usuario, perfil, "Almacen Masivo");
    }
     
    public void insertar_masivo_productos_x_almacen(int idAlmacen, List<Integer> idproductos, List<Integer> capacidades) {
        
        ObjectContext context = DataContext.createDataContext();
          Estado e = new Estado();
        int cont=0;
        while (cont<capacidades.size())
        {   AlmacenXProducto p = context.newObject(AlmacenXProducto.class);
        
         Expression qualifiers = ExpressionFactory.matchExp(Producto.IDPRODUCTO_PROPERTY,String.valueOf(idproductos.get(0)));
           SelectQuery selects = new SelectQuery(Producto.class, qualifiers);
           Producto prod = (Producto)DataObjectUtils.objectForQuery(context, selects);
            
          Almacen a=this.buscarPorId(context, idAlmacen);
           
           
            p.setToProducto(prod);
            p.setToAlmacen(a);
            p.setCapacidad(capacidades.get(cont));
            p.setEstado(e.getSinUsar());
            p.setStock(0);
            context.commitChanges(); 
            cont++;
        }         
        
        context.commitChanges();
         String usuario=LoginT.userLogin.getUsuario();
        String perfil=LoginT.perfilLogin.getDescripcion();
        AuditoriaService as = new AuditoriaService();
        as.auditoriaInsert(usuario, perfil, "Almacen Masivo");
    }
    public boolean seEncuentra(int id,List<AlmacenXProducto> lista ){
        boolean aux=false;
        for(int i=0;i<lista.size();i++){
            if (id == lista.get(i).getToProducto().getIdproducto()){
                aux = true;break;
            }
        }
        return aux;
    }
    
    public int verificaYelimina(ObjectContext context,List<AlmacenXProducto> pasados ,List<Integer> actuales){
        boolean esta=false;
        int salida=1;
        AlmacenXProductoService serv = new AlmacenXProductoService();
        int id; 
        for(int i=0;i<pasados.size();i++){
            for(int j=0;j<actuales.size();j++){
                id=pasados.get(i).getToProducto().getIdproducto();
                if (id==actuales.get(j)){
                    esta=true;break;
                }
            }
            if(!esta){//Si no esta en la lista actual elimino
                int idPas = pasados.get(i).getIdalmacenxproducto();
                if(pasados.get(i).getStock()==0){// Si el stock es igual a cero se puede eliminar
                    serv.eliminarPorIdAxP(context,idPas);
                }
                else 
                    salida=2;//Se trata de eliminar un almacen x producto en uso
            }          
            esta=false;
        }
        return salida;
    }
    
    public int editar(int idAlm,int idZona, String descripcion, String direccion, List<Integer> idproductos, List<Integer> capacidades){
        
         String usuario=LoginT.userLogin.getUsuario();
        String perfil=LoginT.perfilLogin.getDescripcion();
        AuditoriaService as = new AuditoriaService();
        as.auditoriaUpdate(usuario, perfil, "Almacen");
        ObjectContext context = DataContext.createDataContext();
        Almacen a = this.buscarPorId(context, idAlm);  
        Estado e = new Estado();
        //Obtiene la zona
        Expression qualifier = ExpressionFactory.matchExp(Zona.IDZONA_PROPERTY,String.valueOf(idZona));
        SelectQuery select = new SelectQuery(Zona.class, qualifier);
        Zona z = (Zona) DataObjectUtils.objectForQuery(context, select);
              
        a.setDescripcion(descripcion);
        a.setDireccion(direccion);
        a.setToZona(z);
        
        int salida1 = 1;//Se modifico de forma exitosa
        int salida2 = 1;//Se elimino de forma exitosa 
        int salida3 = 1;
        AlmacenXProductoService serv = new AlmacenXProductoService();
        List<AlmacenXProducto> lista = serv.buscarPorIdAlm(context, idAlm);//Lista en la base de datos
        
        //serv.eliminarPorIdAlm(context, idAlm);
        int cont=0;
        //Verificar la lista nueva
        while (cont < idproductos.size()){
            AlmacenXProducto p;
            
            Expression qualifiers = ExpressionFactory.matchExp(Producto.IDPRODUCTO_PROPERTY,String.valueOf(idproductos.get(cont)));
            SelectQuery selects = new SelectQuery(Producto.class, qualifiers);
            Producto prod = (Producto)DataObjectUtils.objectForQuery(context, selects);
            
            int nuevaCap = capacidades.get(cont);
            if(seEncuentra(idproductos.get(cont),lista)){//Se edita                
                p = lista.get(cont);
                
                KardexService servK = new KardexService();
                if(nuevaCap>lista.get(cont).getStock()){//Verifica que en caso haya stock no se coloque menos capacidad que este
                    if(!servK.AlmacenXProductoPendiente(p.getIdalmacenxproducto()))                
                        p.setCapacidad(nuevaCap);
                    else 
                        salida1=2;//No se pudo cambiar la capacidad de una parte del almacen debido a su uso
                }
                else 
                    salida3=2;//No se pudo cambiar por que es menor q el stock actual
            }
            else{//se crea                
                p = context.newObject(AlmacenXProducto.class);
                p.setToProducto(prod);
                p.setToAlmacen(a);
                p.setCapacidad(nuevaCap);
                p.setEstado(e.getSinUsar());
                p.setStock(0);
            }
            
            context.commitChanges(); 
            cont++;
        }
        int ver =verificaYelimina(context,lista, idproductos);
        if (ver==2) salida2 = 2;  
        if(salida3==2)
            return 5;
        if(salida1==2&&salida2==2)
            return 2;//Se elimino un registro usado y se modifico un registro que esta en uso
        else if(salida1==2)
            return 3;//se modifico un registro que esta en uso
        else if(salida2==2)
            return 4;//Se elimino un registro usado 
        else
            return 1;//Modificación exitosa
        
    }
    public boolean esTemporal(ObjectContext c,int idAlm){
        
        String cadena = "select * from almacen where idalmacen = "+idAlm+" and descripcion ilike '%Temporal%'";
        SQLTemplate query = new SQLTemplate(AlmacenXProducto.class,cadena);        
        List<AlmacenXProducto> almacenes = c.performQuery(query); 
        if(almacenes.isEmpty())
            return false;
        else 
            return true;
    }
    public int eliminar(int idAlm){
        
         String usuario=LoginT.userLogin.getUsuario();
        String perfil=LoginT.perfilLogin.getDescripcion();
        AuditoriaService as = new AuditoriaService();
        as.auditoriaDelete(usuario, perfil, "Almacen");
        ObjectContext context = DataContext.createDataContext();
        Estado est = new Estado();
        KardexService servMov = new KardexService();
        
        if(!servMov.almUtilizado(context,idAlm)){
            if(esTemporal(context,idAlm)){
                return 2;
            }
            else{
                AlmacenXProductoService serv = new AlmacenXProductoService();
                serv.eliminarPorIdAlm(context,idAlm);//Elimina todos los elementos de la tabla intermedia almacen x 

                Almacen e = this.buscarPorId(context,idAlm);
                e.setEstado(est.getEliminado());
                context.commitChanges();
                return 1;
            }
        }
        else 
            return 0;
    }
    
    public List<Almacen> buscarFiltrado(String descripcion, String direccion, int idProd,int estado) {        
        
        ObjectContext context = DataContext.createDataContext();
        String cadena = "select * from almacen where idAlmacen in "
                + "(select p.idAlmacen"
                + " from almacen a, almacen_x_producto p"
                + " where a.idAlmacen = p.idAlmacen and a.descripcion like '%"+descripcion+"%' "
                + " and a.direccion like '%"+direccion+"%' and p.estado >= 1";
        
        String cadena2; if(idProd!=0){cadena2=" and p.idProducto = "+idProd+"";}else{cadena2="";}
        String cadena3; if(estado!=-1){cadena3=" and a.estado = "+estado+")";}else{cadena3=")";}
        String cad = cadena+cadena2+cadena3;
        
        SQLTemplate query = new SQLTemplate(Almacen.class,cad);         
        List<Almacen> tipos = context.performQuery(query);
        
        return tipos;
    }

    public List<Almacen> buscarFiltrado(String descripcion, String direccion) {
        ObjectContext context = DataContext.createDataContext();
        String cadena = "select * from almacen "
                + " where descripcion like '%"+descripcion+"%' "
                + " and direccion like '%"+direccion+"%'"
                + " and estado >= 1";
        SQLTemplate query = new SQLTemplate(Almacen.class,cadena);         
        List<Almacen> tipos = context.performQuery(query);
        
        return tipos;
    }

    public List<Almacen> buscar() {
        ObjectContext context = DataContext.createDataContext();
        String cadena = "SELECT * FROM ALMACEN WHERE ESTADO > 0 and idalmacen in(select idalmacen from almacen where descripcion not like '%Temporal%')";
        SQLTemplate query = new SQLTemplate(Almacen.class,cadena);        
        List<Almacen> almacenes = context.performQuery(query);       
        return almacenes;
    }
    
    public List<Almacen> buscarTodos() {
        ObjectContext context = DataContext.createDataContext();
        String cadena = "SELECT * FROM ALMACEN WHERE ESTADO > 0";
        SQLTemplate query = new SQLTemplate(Almacen.class,cadena);        
        List<Almacen> almacenes = context.performQuery(query);       
        return almacenes;
    }
    public String verificaStockProductos(){//Para mandar mensaje de alerta
        String cadena ="Los siguientes productos tienen stock por debajo de los niveles aceptados:\n\n";
        boolean alerta=false;
        ProductoService servP = new ProductoService();
        List<Producto> productos = servP.buscarTodo();
        int i;
        for(i=0;i<productos.size();i++){
            if(productos.get(i).getToTipoProducto().getIdtipoproducto()==3)//El producto es prod terminado no se considera y se elimina de la lista
                productos.remove(i);
            else{//El producto es insumo o prod interm
                List<Integer> disp = capacidad_StockTotalProducto(productos.get(i).getIdproducto());
                int stock = disp.get(1);//Stock actual del producto analizado
                int stockMin = productos.get(i).getStockmin();
                if(disp.get(0)!=0){//El producto a sido almacenado
                    if(stock<stockMin){
                        cadena+=productos.get(i).getDescripcion()+" - stock mínimo: "+stockMin+" - stock actual: "+stock+"\n";
                        alerta=true;
                    }
                }//En caso contrario el prod aun no ha sido almacenado en algun almacen                
            }
        }
        if (alerta)
            return cadena;// Hay productos para alertar
        else 
            return null;
    }
    public List<Integer> capacidad_StockTotalProducto(int idProd){
            
        ObjectContext c = DataContext.createDataContext();
        
        AlmacenXProductoService serv = new AlmacenXProductoService();
        
        List<AlmacenXProducto> listAlm = serv.buscarPorIdProd(c, idProd);
        List<Integer> disp = new ArrayList<Integer>();
        
        if(!listAlm.isEmpty()){
            int tam=listAlm.size();
            int capacidadT=0;
            int stockT=0;

            for(int i=0;i<tam;i++){//Calcula la capacidad total de la empresa de guardar el producto y su stock total
                capacidadT+=listAlm.get(i).getCapacidad()-listAlm.get(i).getStock();            
                stockT+=listAlm.get(i).getStock();
            }
            disp.add(capacidadT);
            disp.add(stockT);
        }
        else{
            disp.add(0);
            disp.add(0);
        }
        
        return disp;
    }
    
    //Este método retorna 1 en caso el movimiento se realice correctamente
    //Retornará la capacidad total o stock total dependiendo sea entrada o salida
    public int movimientoAlmacen(int idDocumento,int idProd,int idTMov,int cant){
        
        ObjectContext c = DataContext.createDataContext();
        
        int tam;//Cantidad de almacenes donde ingresar/retirar productos
        int capacidadT=0;//La capacidad max para guardar el producto en todos los almacenes
        int stockT=0;//El stock max del producto en todos los almacenes
        
        AlmacenXProductoService serv = new AlmacenXProductoService();
        TipoMovimientoService servTm = new TipoMovimientoService();
        List<AlmacenXProducto> listAlm = serv.buscarPorIdProd(c, idProd);
        tam=listAlm.size();
        
        for(int i=0;i<tam;i++){//Calcula la capacidad total de la empresa de guardar el producto y su stock total
            capacidadT+=listAlm.get(i).getCapacidad()-listAlm.get(i).getStock();
            stockT+=listAlm.get(i).getStock();
        }
        
        //Verifico que la capacidad total en los almacenes permita guardar dicho movimiento
        if(servTm.verificaTipoMov(idTMov,"Entrada")){//Entrada a almacen
            if(capacidadT>=cant){ //Verificación de capacidad total
                KardexService servMov = new KardexService();

                for(int i=0;i<tam;i++){

                        int idAlm = listAlm.get(i).getToAlmacen().getIdalmacen();
                        List<Integer> alm = servMov.disponibilidad(idAlm, idProd);
                        int capacidadDisponible = alm.get(0);
                        int cantIn;

                        if(cant>capacidadDisponible)
                            cantIn=capacidadDisponible;
                        else
                            cantIn=cant;
                        servMov.insertarMovimientoPendiente(idDocumento,idAlm, idProd,idTMov, cantIn);
                        cant-=cantIn;

                        if(cant==0) break;
                }
                return 1; //Caso en el que se logro mandar un movimiento como pendiente
            }
            else
                return capacidadT;
        }
        else if(servTm.verificaTipoMov(idTMov,"Salida")){
            if(capacidadT>=cant){                
                KardexService servMov = new KardexService();
                
                if(stockT>=cant){//Hay producto en stock para la demanda
                        
                    for(int i=0;i<tam;i++){

                        int idAlm = listAlm.get(i).getToAlmacen().getIdalmacen();
                        List<Integer> alm = servMov.disponibilidad(idAlm, idProd);
                        int stockDisponible = alm.get(1);
                        int cantIn;

                        if(cant>stockDisponible)
                            cantIn=stockDisponible;
                        else
                            cantIn=cant;
                        if(idTMov==4)
                            servMov.insertarMovimientoVenta(idDocumento,idAlm, idProd,idTMov, cantIn);
                        else                            
                            servMov.insertarMovimientoPendiente(idDocumento,idAlm, idProd,idTMov, cantIn);
                        cant-=cantIn;

                        if(cant==0) break;
                    }
                    return 1; 
                }
                else {//No hay producto en stock para la demanda
                    for(int i=0;i<tam;i++){

                        int idAlm = listAlm.get(i).getToAlmacen().getIdalmacen();
                        List<Integer> alm = servMov.disponibilidad(idAlm, idProd);
                        int capacidadDisponible = alm.get(0);
                        int cantIn;

                        if(cant>capacidadDisponible)
                            cantIn=capacidadDisponible;
                        else
                            cantIn=cant;
                        servMov.insertarMovimientoPendiente(idDocumento,idAlm, idProd,idTMov, cantIn);
                        cant-=cantIn;

                        if(cant==0) break;
                    }
                    return stockT;
                }
                    
            }
            else 
                return capacidadT;
        }
        else
            return 0;//En caso el id no exista o no verifique si es entrada o salida       
    }

}
